package main

import (
	"errors"
	"fmt"
	"strings"
)

func main() {

	/*
		三. 函数变量（函数作为值）

		TIPS：
			① 在Go语言中，函数也是一种类型，可以和其他类型（如int32、float等等）一样被保存在变量中，这就是所谓的函数式编程；
			② 在Go语言中可以通过type来定义一个自定义类型。函数的参数完全相同（包括参数类型、个数、顺序），函数返回值相同；
	*/

	// 1. 函数作为参数
	str := "FDFFREGCDfferttrfdfdf"
	fmt.Println(processCass(str))
	// 使用一个指定函数作为参数
	fmt.Println(processCassAndPrint(str, processCass))
	// 只要 函数的参数完全相同（包括参数类型、个数、顺序），函数返回值相同，其他函数也一样可以被调用
	fmt.Println(processCassAndPrint(str, processCass1))
	// 使用匿名函数直接作为参数
	fmt.Println(processCassAndPrint(str, func(s string) string {
		result := ""
		for index, value := range str {
			if index%2 == 0 {
				result += strings.ToUpper(string(value))
			} else {
				result += strings.ToLower(string(value))
			}
		}
		return result
	}))
	// 函数通过 type 自定义类型
	fmt.Println(processCassAndPrint2(str, processCass))

	// 2. 函数作为返回值
	if o, err := getFunc("*"); err != nil {
		fmt.Printf("调用异常：%s", err.Error())
	} else {
		i := o(1, 2)
		fmt.Printf("计算结果：%d", i)
	}
}

/*
处理字符串，奇数偶数依次大小写展示

TIPS：如果只有一个返回值并且没有声明返回值变量，那么可以省略包括返回值的括号
*/
func processCass(str string) string {

	result := ""
	for index, value := range str {
		if index%2 == 0 {
			result += strings.ToUpper(string(value))
		} else {
			result += strings.ToLower(string(value))
		}
	}
	return result
}

func processCass1(str string) string {

	result := ""
	for index, value := range str {
		if index%3 == 0 {
			result += strings.ToLower(string(value))
		} else {
			result += strings.ToUpper(string(value))
		}
	}
	return result
}

/*
打印变量f的类型，再大小写处理
*/
func processCassAndPrint(str string, f func(string) string) string {

	// 打印变量f的类型
	fmt.Printf("%T \n", f)

	return f(str)
}

/*
声明一个函数类型，通过type关键字来实现一个自定义类型
*/
type caseFunction func(string) string

/*
打印变量f的类型，再大小写处理。参数类型为一个自定义类型
*/
func processCassAndPrint2(str string, f caseFunction) string {

	// 打印变量f的类型
	fmt.Printf("%T \n", f)

	return f(str)
}

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}

type operation func(x, y int) int

func getFunc(s string) (operation, error) {

	switch s {
	case "+":
		return add, nil
	case "-":
		return sub, nil
	default:
		err := errors.New("无法识别的操作符")
		return nil, err
	}
}
